/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation;
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#include "ns3/netanim-module.h"
#include "ns3/core-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/network-module.h"
#include "ns3/applications-module.h"
#include "ns3/wifi-module.h"
#include "ns3/mobility-module.h"
#include "ns3/csma-module.h"
#include "ns3/internet-module.h"

// Default Network Topology
//
//   Wifi 10.1.3.0
//                 AP
//  *    *    *    *
//  |    |    |    |    10.1.1.0
// n5   n6   n7   n0 -------------- n1   n2   n3   n4
//                   point-to-point  |    |    |    |
//                                   ================
//                                     LAN 10.1.2.0

using namespace ns3;

NS_LOG_COMPONENT_DEFINE ("ThirdScriptExample");

int 
main (int argc, char *argv[])
{
  bool verbose = true;
  unsigned int nCsma = 0;
  unsigned int nWifi = 3;

  CommandLine cmd;
  cmd.AddValue ("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma);
  cmd.AddValue ("nWifi", "Number of wifi STA devices", nWifi);
  cmd.AddValue ("verbose", "Tell echo applications to log if true", verbose);

  cmd.Parse (argc,argv);

  if (nWifi > 18)
    {
      std::cout << "Number of wifi nodes " << nWifi << 
                   " specified exceeds the mobility bounding box" << std::endl;
      exit (1);
    }

  if (verbose)
    {
      LogComponentEnable ("UdpEchoClientApplication", LOG_LEVEL_INFO);
      LogComponentEnable ("UdpEchoServerApplication", LOG_LEVEL_INFO);
    }

  NodeContainer p2pNodes;
  p2pNodes.Create (2);

//  NodeContainer p2pNodes2;
//  p2pNodes2.Create (2);

  PointToPointHelper pointToPoint;
  pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
  pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));

  NetDeviceContainer p2pDevices;
  p2pDevices = pointToPoint.Install (p2pNodes);


//  NetDeviceContainer p2pDevices2;
//  p2pDevices2 = pointToPoint.Install (p2pNodes2);

  NodeContainer csmaNodes;
  csmaNodes.Add (p2pNodes.Get (1));
  csmaNodes.Create (nCsma);

//  NodeContainer csmaNodes2;
//  csmaNodes2.Add (p2pNodes2.Get (1));
//  csmaNodes2.Create (nCsma);


  CsmaHelper csma;
  csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps"));
  csma.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560)));

  NetDeviceContainer csmaDevices;
  csmaDevices = csma.Install (csmaNodes);

//  NetDeviceContainer csmaDevices2;
//  csmaDevices2 = csma.Install (csmaNodes2);

  NodeContainer wifiStaNodes;
  wifiStaNodes.Create (nWifi);
  NodeContainer wifiApNode = p2pNodes.Get (0);

  
//  NodeContainer wifiStaNodes2;
//  wifiStaNodes2.Create (nWifi);
//  NodeContainer wifiApNode2 = p2pNodes2.Get (0);


  YansWifiChannelHelper channel = YansWifiChannelHelper::Default ();
  YansWifiPhyHelper phy = YansWifiPhyHelper::Default ();
  phy.SetChannel (channel.Create ());






  WifiHelper wifi = WifiHelper::Default ();
  wifi.SetRemoteStationManager ("ns3::AarfWifiManager");


//  WifiHelper wifi2 = WifiHelper::Default ();
 // wifi2.SetRemoteStationManager ("ns3::AarfWifiManager");

  NqosWifiMacHelper mac = NqosWifiMacHelper::Default ();
//  NqosWifiMacHelper mac2 = NqosWifiMacHelper::Default ();




  Ssid ssid = Ssid ("ns-3-ssid");
  mac.SetType ("ns3::StaWifiMac",
               "Ssid", SsidValue (ssid),
               "ActiveProbing", BooleanValue (false));


//  Ssid ssid2 = Ssid ("ns-3-ssid2");
//  mac2.SetType ("ns3::StaWifiMac",
//              "Ssid", SsidValue (ssid2),
//              "ActiveProbing", BooleanValue (false));


  NetDeviceContainer staDevices;
  staDevices = wifi.Install (phy, mac, wifiStaNodes);


//  NetDeviceContainer staDevices2;
//  staDevices2 = wifi2.Install (phy, mac2, wifiStaNodes2);


  mac.SetType ("ns3::ApWifiMac",
               "Ssid", SsidValue (ssid));


//  mac2.SetType ("ns3::ApWifiMac",
//               "Ssid", SsidValue (ssid2));

  NetDeviceContainer apDevices;
  apDevices = wifi.Install (phy, mac, wifiApNode);

//  NetDeviceContainer apDevices2;
//  apDevices2 = wifi2.Install (phy, mac2, wifiApNode2);























  MobilityHelper mobility;

//  MobilityHelper mobility2;

  mobility.SetPositionAllocator ("ns3::GridPositionAllocator",
                                 "MinX", DoubleValue (0.0),
                                 "MinY", DoubleValue (0.0),
                                 "DeltaX", DoubleValue (5.0),
                                 "DeltaY", DoubleValue (5.0),
                                 "GridWidth", UintegerValue (3),
                                 "LayoutType", StringValue ("RowFirst"));

//  mobility2.SetPositionAllocator ("ns3::GridPositionAllocator",
  //                               "MinX", DoubleValue (0.0),
    //                             "MinY", DoubleValue (0.0),
      //                           "DeltaX", DoubleValue (5.0),
        //                         "DeltaY", DoubleValue (5.0),
          //                       "GridWidth", UintegerValue (3),
            //                     "LayoutType", StringValue ("RowFirst"));


  mobility.SetMobilityModel ("ns3::RandomWalk2dMobilityModel",
                             "Bounds", RectangleValue (Rectangle (-10, 10, -10, 10)));
  mobility.Install (wifiStaNodes);


//  mobility2.SetMobilityModel ("ns3::RandomWalk2dMobilityModel",
  //                           "Bounds", RectangleValue (Rectangle (-20, 20, -20, 20)));

 // mobility2.Install (wifiStaNodes2);


  mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
  mobility.Install (wifiApNode);

//  mobility2.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
//  mobility2.Install (wifiApNode2);



  InternetStackHelper stack;
  stack.Install (csmaNodes);
  stack.Install (wifiApNode);
  stack.Install (wifiStaNodes);


//  InternetStackHelper stack2;
//  stack2.Install (csmaNodes2);
//  stack2.Install (wifiApNode2);
//  stack2.Install (wifiStaNodes2);

  Ipv4AddressHelper address;
  Ipv4AddressHelper address2;


  address.SetBase ("10.1.1.0", "255.255.255.0");
  Ipv4InterfaceContainer p2pInterfaces;
  p2pInterfaces = address.Assign (p2pDevices);

//  address2.SetBase ("10.2.1.0", "255.255.255.0");
//  Ipv4InterfaceContainer p2pInterfaces2;
//  p2pInterfaces2 = address2.Assign (p2pDevices2);



  address.SetBase ("10.1.2.0", "255.255.255.0");
  Ipv4InterfaceContainer csmaInterfaces;
  csmaInterfaces = address.Assign (csmaDevices);

//  address2.SetBase ("10.2.2.0", "255.255.255.0");
//  Ipv4InterfaceContainer csmaInterfaces2;
//  csmaInterfaces2 = address2.Assign (csmaDevices2);




  address.SetBase ("10.1.3.0", "255.255.255.0");
  address.Assign (staDevices);
  address.Assign (apDevices);

//  address2.SetBase ("10.2.3.0", "255.255.255.0");
//  address2.Assign (staDevices2);
//  address2.Assign (apDevices2);



  UdpEchoServerHelper echoServer (9);
  UdpEchoServerHelper echoServer2 (9);



  ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma));
  serverApps.Start (Seconds (1.0));
  serverApps.Stop (Seconds (10.0));


//  ApplicationContainer serverApps2 = echoServer2.Install (csmaNodes2.Get (nCsma));
//  serverApps2.Start (Seconds (1.0));
//  serverApps2.Stop (Seconds (10.0));



  UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9);
  echoClient.SetAttribute ("MaxPackets", UintegerValue (10));
  echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.0)));
  echoClient.SetAttribute ("PacketSize", UintegerValue (1024));

//  UdpEchoClientHelper echoClient2 (csmaInterfaces2.GetAddress (nCsma), 9);
//  echoClient2.SetAttribute ("MaxPackets", UintegerValue (10));
//  echoClient2.SetAttribute ("Interval", TimeValue (Seconds (1.0)));
//  echoClient2.SetAttribute ("PacketSize", UintegerValue (1024));



  ApplicationContainer clientApps = 
  echoClient.Install (wifiStaNodes.Get (nWifi - 1));
  clientApps.Start (Seconds (2.0));
  clientApps.Stop (Seconds (10.0));

//  ApplicationContainer clientApps2 = 
//  echoClient2.Install (wifiStaNodes2.Get (nWifi - 1));
//  clientApps2.Start (Seconds (2.0));
//  clientApps2.Stop (Seconds (10.0));


  Ipv4GlobalRoutingHelper::PopulateRoutingTables ();

  Simulator::Stop (Seconds (10.0));

//  pointToPoint.EnablePcapAll ("third");
 // phy.EnablePcap ("third", apDevices.Get (0));
 // csma.EnablePcap ("third", csmaDevices.Get (0), true);

// Visualization by Jinho Kim

AnimationInterface anim ("myCCA.xml");

anim.SetConstantPosition (p2pNodes.Get(0), 5.0, 5.0);
anim.SetConstantPosition (p2pNodes.Get(1), 5.0, 10.0);


//anim.SetConstantPosition (p2pNodes2.Get(0), 10.0, 5.0);
//anim.SetConstantPosition (p2pNodes2.Get(1), 10.0, 10.0);
/*
while ((nCsma+1)>0)
{
anim.SetConstantPosition (csmaNodes.Get(nCsma), nCsma,0.0);
nCsma--;
printf("nCsma =  %d\n",nCsma);
}
*/

/*
while ((nWifi+1)>0)
{
anim.SetConstantPosition (wifiStaNodes.Get(nWifi), nWifi, 3.0);
nWifi--;
printf("nWifi= %d\n",nWifi);

}
*/
// end of visualization

  Simulator::Run ();
  Simulator::Destroy ();
  return 0;
}
